package wang.wangby.lazydoc.common;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

import wang.wangby.lazydoc.common.parameter.ClassType;
import wang.wangby.lazydoc.common.parameter.GenericType;
import wang.wangby.lazydoc.common.parameter.VarType;
import wang.wangby.utils.ClassUtil;

//文档的参数对象
abstract public class DocParameterType {
	protected Type type;
	protected Type ownerType;
	
	// 获得类型名称
	abstract public String getTypeName();

	// 获得原始类型
	abstract public Class getRawType();

	// 获得持有此类的类型
	 public Type getOwnerType() {
		 return ownerType;
	 }

	// 获得第一个泛型参数所属的类型,如果不是泛型类,就返回本身
	abstract public Class getFirstGenericType();

	// 当前类型是否是数组
	public boolean isArray() {
		return ClassUtil.isArrayClass(getRawType());
	}
	
	
	public DocParameterType(Type type,Type ownerType) {
		this.type=type;
		this.ownerType=ownerType;
	}
	

	public static DocParameterType getType(Type type, Type ownerType) {
		if (type instanceof Class) {
			return new ClassType((Class) type, ownerType);
		}
		if (type instanceof ParameterizedType) {
			ParameterizedType t = (ParameterizedType) type;
			return new GenericType(t, ownerType);
		}

		if( type instanceof TypeVariable) {
			return new VarType(type, ownerType);
		}
		
		throw new RuntimeException("暂时不支持的类型:"+type);
	}

	/**
	 * 获得泛型参数和实际传的类型的对应表,只支持1级,例如List<Map<String,List<String>> 当做List<Map> 处理
	 * 
	 * @param type 必须是已知的类,如方法的参数或返回值
	 */
	public static Map<String, Type> getRealType(Type type) {
		if (type == null) {
			return new HashMap();
		}

		if (!(type instanceof ParameterizedType)) {
			return new HashMap();
		}
		ParameterizedType pType = (ParameterizedType) type;
		Map<String, Type> map = new HashMap();

		TypeVariable[] var = getRawType(pType).getTypeParameters();
		Type[] actualType = pType.getActualTypeArguments();
		for (int i = 0; i < var.length; i++) {
			map.put(var[i].getName(), actualType[i]);
		}

		return map;
	}

	public static Class getRawType(Type type) {
		if (type instanceof Class) {
			return (Class) type;
		}
		ParameterizedType pType = (ParameterizedType) type;
		return getRawType(pType.getRawType());
	}

	

}
